// -----------------------------------------------------------
// Game Framework
// Copyright © 2024-2024 deadcycle. All rights reserved.
// Homepage: https://deadcycle.gitee.io
// Feedback: deadcycle@163.com
// -----------------------------------------------------------

using System;
using System.Collections.Generic;

using UnityEngine;
using UnityEngine.Pool;
using UnityEngine.UI;

namespace UIWidget
{
    /// <summary>
    /// 镜像复制图像效果, 暂时不对9宫与平铺模式进行支持。
    /// </summary>
    [RequireComponent(typeof(Graphic)), DisallowMultipleComponent]
    public class MirrorMeshEffect : BaseMeshEffect
    {
        /// <summary> 镜像方式。 </summary>
        public enum MirrorType
        {
            /// <summary> 水平镜像。 </summary>
            Horizontal,

            /// <summary> 垂直镜像。 </summary>
            Vertical,

            /// <summary> 1/4镜像。 </summary>
            Quarter,
        }

        #region 字段
        [SerializeField]
        private MirrorType m_MirrorType = MirrorType.Horizontal;

        [SerializeField]
        private bool m_FlipMirror;

        private RectTransform m_CacheRectTransform;
        #endregion

        #region 属性

        private RectTransform CacheRectTransform =>
            m_CacheRectTransform ??= GetComponent<RectTransform>();

        /// <summary> 是否翻转复制的镜像图像 </summary>
        public bool FlipMirror
        {
            get => m_FlipMirror;
            set
            {
                if (m_FlipMirror == value)
                {
                    return;
                }

                m_FlipMirror = value;

                if (graphic != null)
                {
                    graphic.SetVerticesDirty();
                }
            }
        }
        #endregion

        public override void ModifyMesh(VertexHelper vh)
        {
            if (!IsActive())
            {
                return;
            }

            List<UIVertex> uiVertices = ListPool<UIVertex>.Get();
            vh.GetUIVertexStream(uiVertices);

            // 两个三角面, 顶点数为6
            if (uiVertices.Count != 6)
            {
                if (graphic is Image { useSpriteMesh: true })
                {
                    Debug.LogWarning(
                        "Image's mirror mesh effect is ineffective due to the vertex count being too large when `use sprite mesh`. (Image处于`use sprite mesh`模式时, 会导致顶点数过多, 使得镜像复制图像效果无效)");
                }
                else
                {
                    Debug.LogWarning(
                        "Graphic's mirror mesh effect is ineffective due to the vertex count being too large. (图像的顶点数过多, 镜像复制图像效果无效)");
                }

                ListPool<UIVertex>.Release(uiVertices);

                return;
            }

            if (graphic is Image image)
            {
                switch (image.type)
                {
                    case Image.Type.Simple:
                        DrawSimple(uiVertices);

                        break;

                    default:
                        Debug.LogWarning(
                            $"Image is using mirror mesh effect, unsupported image type : {image.type} (图片使用镜像复制图像效果时, 不支持非Simple模式)");

                        DrawSimple(uiVertices);

                        break;
                }
            }
            else
            {
                DrawSimple(uiVertices);
            }

            vh.Clear();
            vh.AddUIVertexTriangleStream(uiVertices);

            ListPool<UIVertex>.Release(uiVertices);
        }

        /// <summary>
        /// 设置成原始尺寸。
        /// </summary>
        public void SetNativeSize()
        {
            if (graphic == null)
            {
                return;
            }

            if (graphic is Image image)
            {
                // 这里注意, overrideSprite表示当前状态的sprite, 不能用sprite
                Sprite overrideSprite = image.overrideSprite;

                if (overrideSprite == null)
                {
                    return;
                }

                float w = overrideSprite.rect.width / image.pixelsPerUnit;
                float h = overrideSprite.rect.height / image.pixelsPerUnit;

                // 使RectTransform不会受父级尺寸产生拉伸
                CacheRectTransform.anchorMax = CacheRectTransform.anchorMin;

                switch (m_MirrorType)
                {
                    case MirrorType.Horizontal:
                        CacheRectTransform.sizeDelta = new Vector2(w * 2, h);

                        break;
                    case MirrorType.Vertical:
                        CacheRectTransform.sizeDelta = new Vector2(w, h * 2);

                        break;
                    case MirrorType.Quarter:
                        CacheRectTransform.sizeDelta = new Vector2(w * 2, h * 2);

                        break;
                }

                graphic.SetVerticesDirty();
            }
            else if (graphic is RawImage rawImage)
            {
                Texture texture = rawImage.texture;

                if (texture == null)
                {
                    return;
                }

                float w = texture.width * rawImage.uvRect.width;
                float h = texture.height * rawImage.uvRect.height;

                // 使RectTransform不会受父级尺寸产生拉伸
                CacheRectTransform.anchorMax = CacheRectTransform.anchorMin;

                switch (m_MirrorType)
                {
                    case MirrorType.Horizontal:
                        CacheRectTransform.sizeDelta = new Vector2(w * 2, h);

                        break;
                    case MirrorType.Vertical:
                        CacheRectTransform.sizeDelta = new Vector2(w, h * 2);

                        break;
                    case MirrorType.Quarter:
                        CacheRectTransform.sizeDelta = new Vector2(w * 2, h * 2);

                        break;
                }

                graphic.SetVerticesDirty();
            }
        }

        /// <summary>
        /// 能否设置成原始尺寸。
        /// </summary>
        public bool CanNativeSize()
        {
            if (graphic == null)
            {
                return false;
            }

            if (graphic is Image image)
            {
                return image.overrideSprite != null;
            }

            if (graphic is RawImage rawImage)
            {
                return rawImage.texture != null;
            }

            return false;
        }

        /// <summary>
        /// 绘制Simple模式的图像效果。
        /// </summary>
        protected void DrawSimple(List<UIVertex> vertexList)
        {
            // 获取当前图形Graphic矩形绘制范围, 用于做后面顶点的偏移
            Rect rect = graphic.GetPixelAdjustedRect();

            // 根据镜像方式, 修改原始顶点数据信息为后续复制镜像做准备 
            SimpleVertexPrepare(rect, vertexList);

            int count = vertexList.Count;

            /* 开始对顶点进行镜像, 镜像前先对列表进行扩容
             * 在镜像顶点时, 需要往列表添加多个顶点, 可能产生性能问题
             * 最后对顶点进行镜像, 1/2(水平与垂直)镜像需要扩充1倍容量, 1/4镜像需要扩充3倍顶点容量
             */
            switch (m_MirrorType)
            {
                case MirrorType.Horizontal:
                    ExtendCapacity(vertexList, count);
                    HorizontalMirrorVerts(rect, vertexList, true);

                    break;
                case MirrorType.Vertical:
                    ExtendCapacity(vertexList, count);
                    VerticalMirrorVerts(rect, vertexList, true);

                    break;
                case MirrorType.Quarter:
                    ExtendCapacity(vertexList, count * 3);
                    HorizontalMirrorVerts(rect, vertexList, false);
                    VerticalMirrorVerts(rect, vertexList, false);

                    break;
            }
        }

        /// <summary>
        /// Simple模式下, 对原始顶点的预处理修改。
        /// </summary>
        protected void SimpleVertexPrepare(Rect rect, List<UIVertex> vertexList)
        {
            for (int i = 0; i < vertexList.Count; i++)
            {
                UIVertex vertex = vertexList[i];
                Vector3 position = vertex.position;

                // 注意rect, position都是相对于RectTransform中心的, 并非uv范围值
                // 如果直接缩放是围绕RectTransform中心点, 需要以Rect边框, 左边与底边为缩放轴
                if (m_MirrorType is MirrorType.Horizontal or MirrorType.Quarter)
                {
                    position.x = (position.x + rect.x) * 0.5f;
                }

                if (m_MirrorType is MirrorType.Vertical or MirrorType.Quarter)
                {
                    position.y = (position.y + rect.y) * 0.5f;
                }

                vertex.position = position;

                vertexList[i] = vertex;
            }
        }

        /// <summary>
        /// 对顶点列表进行扩容, 填充复制的镜像顶点。
        /// </summary>
        protected void ExtendCapacity(List<UIVertex> vertexList, int addCount)
        {
            int needCapacity = vertexList.Count + addCount;

            if (vertexList.Capacity < needCapacity)
            {
                vertexList.Capacity = needCapacity;
            }
        }

        /// <summary>
        /// 以水平镜像方式进行顶点复制。
        /// </summary>
        private void HorizontalMirrorVerts(Rect rect, List<UIVertex> vertexList, bool canFlipMirror)
        {
            MirrorVerts(rect, vertexList, true, canFlipMirror);
        }

        /// <summary>
        /// 以垂直镜像方式进行顶点复制。
        /// </summary>
        protected void VerticalMirrorVerts(Rect rect, List<UIVertex> vertexList, bool canFlipMirror)
        {
            MirrorVerts(rect, vertexList, false, canFlipMirror);
        }

        /// <summary>
        /// 对顶点进行镜像复制操作。
        /// </summary>
        protected void MirrorVerts(Rect rect, List<UIVertex> vertexList, bool isHorizontal,
            bool canFlipMirror)
        {
            bool flipMirror = canFlipMirror && FlipMirror;

            int count = vertexList.Count;

            for (int i = 0; i < count; i++)
            {
                // 注意UIVertex是结构体, 这里得到的是拷贝
                UIVertex vertex = vertexList[i];
                Vector3 position = vertex.position;

                // 这里需要以Rect中心点为对称轴, 顶点进行翻转(这样图像才能对称翻转), 而不是平移
                // 根据两对称点到对称轴距离相等, px1 - cx = cx - px2, 推算出如下公式
                if (isHorizontal)
                {
                    position.x = rect.center.x * 2 - position.x;

                    if (flipMirror)
                    {
                        position.y = rect.center.y * 2 - position.y;
                    }
                }
                else
                {
                    position.y = rect.center.y * 2 - position.y;

                    if (flipMirror)
                    {
                        position.x = rect.center.x * 2 - position.x;
                    }
                }

                // 仅修改顶点的位置数据, 添加新的顶点
                vertex.position = position;
                vertexList.Add(vertex);
            }
        }

        /// <summary>
        /// 效果无效。
        /// </summary>
        /// <returns></returns>
        private bool EffectInvalid()
        {
            if (graphic is not Image image)
            {
                return graphic is not RawImage;
            }

            if (image.useSpriteMesh)
            {
                return true;
            }

            return image.type != Image.Type.Simple;
        }
    }
}